/**
 * 
 */
package com.p2p.front.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.p2p.base.cache.Cache;
import com.p2p.base.model.Money;
import com.p2p.base.util.DateUtil;
import com.p2p.front.dal.dao.LoanVariationDao;
import com.p2p.front.dal.model.LoanInfo;
import com.p2p.front.dal.model.LoanVariation;
import com.p2p.front.service.LoanInfoService;
import com.p2p.front.service.LoanRepayService;
import com.p2p.front.service.LoanVariationService;
import com.p2p.front.service.TenderAutoService;
import com.p2p.front.util.RateUtil;


@Service("loanVariationService")
public class LoanVariationServiceImpl implements LoanVariationService {
	private final Logger logger = LoggerFactory.getLogger(LoanVariationServiceImpl.class);
	
	@Resource
	LoanVariationDao loanVariationDao;
	
	@Resource
	LoanInfoService loanInfoService;
	
	@Resource
	LoanRepayService loanRepayService;
	
	@Resource
	private Cache defaultCache;
	
	@Resource
	private TenderAutoService tenderAutoService;
	
	@Override
	public LoanVariation getByLoanId(Long loanId) {
		return loanVariationDao.getByLoanId(loanId);
	}

	@Override
	public void create(LoanVariation LoanVariation) {
		loanVariationDao.create(LoanVariation);
	}

	@Override
	public boolean update(LoanVariation LoanVariation) {
		return 1==loanVariationDao.update(LoanVariation);
	}

	@Override
	public LoanVariation selectByIdForUpdate(Long loanId) {
		return loanVariationDao.getByLoanIdForLock(loanId);
	}

	


	@Transactional(propagation=Propagation.MANDATORY)
	public LoanVariation getAndLockById(Long lid,LoanInfo loanInfo){
		LoanVariation loanStatus = this.selectByIdForUpdate(lid);
		if(loanStatus==null){
			boolean create = this.createLoanStatus(lid,loanInfo);
			if(create){
				loanStatus = this.selectByIdForUpdate(lid);
			}
		}
		if(loanStatus!=null&&loanStatus.getStatus()==11){
			if(loanInfo==null){
				loanInfo = loanInfoService.getLoanInfoById(lid);
			}
			if(loanInfo!=null){
				int tenderStatus = loanInfo.checkStatusCanTender();
				if(tenderStatus==0){
					return loanStatus;
				}
				
				if(tenderStatus==2){
					loanInfoService.updateStatus(lid, 21);			
				}
				this.updateStatus(lid, 21, 11);
				//tenderAutoService.startAutoQueue(loanInfo);
			}
		}
		return loanStatus;
	}
	
	@Transactional(propagation=Propagation.NOT_SUPPORTED)
	public boolean createLoanStatus(Long lid,LoanInfo loanInfo){
		
		if(loanInfo==null){
			loanInfo = loanInfoService.getLoanInfoById(lid);
		}
		
		if(loanInfo==null){
			return false;
		}
		
		int tenderStatus = loanInfo.checkStatusCanTender();
		
		if(tenderStatus==0){
			return false;
		}
		LoanVariation newloanStatus = new LoanVariation();
		newloanStatus.setStatus(21);
		if(tenderStatus==2){
			loanInfoService.updateStatus(lid, 21);			
		}
		
		newloanStatus.setLoanId(loanInfo.getLid());
		newloanStatus.setAmount(loanInfo.getAmount());
		newloanStatus.setTenderBegin(loanInfo.getTenderBegin());
		newloanStatus.setExpiredTime(loanInfo.getExptime());
		try {
			this.create(newloanStatus);
			//tenderAutoService.startAutoQueue(loanInfo);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return true;
	}

	/*@Override
	public void changeStatus(Long loanId,int status) {
		switch(status){
		
		case 1://投标完成，
			dofinish(loanId);
			return;
		case 2://投标未满额
			doEnd(loanId);
			return;
		}
	}*/
	
	private void dofinish(Long loanId){
		LoanInfo loanInfo = loanInfoService.getLoanInfoById(loanId);
		loanInfoService.updateStatus(loanId, 32);
		//this.changeStatus(loanId, 32);
		if(loanInfo.getIsFlow()==1){
			
		}
		
	}
	
	private void doEnd(Long loanId){
		LoanInfo loanInfo = loanInfoService.getLoanInfoById(loanId);
		if(loanInfo.getIsFlow()==1){
			LoanVariation loanVariation  = this.getByLoanId(loanId);
			
			if(this.updateStatus(loanVariation, 32)){
				loanInfoService.updateStatus(loanId, 32);//32满标
			}
			
		}else{

			LoanVariation loanVariation  = this.getByLoanId(loanId);
			if(this.updateStatus(loanVariation, 31)){
				loanInfoService.updateStatus(loanId, 31);//32满标
			}
		}
		
	}
	
	/*private void doLoanSuccese(Long loanId){
		LoanInfo loanInfo = loanInfoService.getLoanInfoById(loanId);
		LoanStatus loanStatus = this.getLoanStatusById(loanId);
		Money totalTenderAmount = loanStatus.getTenderAmount();
		
		
	}*/

	@Override
	public boolean updateStatusForTenderFull(Long loanId,LoanInfo loanInfo) {
		
		LoanVariation loanVariation  = this.getByLoanId(loanId);
		if(loanVariation.getStatus()!=21){
			return false;
		}
		Money allInterest = RateUtil.getAllInterest(loanInfo.getApr(),
				loanInfo.getDeadline(), loanVariation.getTenderAmount(), loanInfo.getRepayMethod());
		if(1==loanVariationDao.updateStatusFroFullTender(loanVariation)){
			//LoanInfo loanInfo = loanInfoService.getLoanInfoById(loanVariation.getLoanId());
			return loanInfoService.updateStatus(loanId, 32,21);
		}
		return false;
	}

	@Override
	public boolean updateStatusForRepay(Long loanId,Money totalInterest) {
		LoanVariation loanVariation  = this.getByLoanId(loanId);
		
		if(loanVariation.getStatus()!=32){
			return false;
		}
		loanVariation.setTotalInterest(totalInterest);
		if(this.updateStatus(loanVariation, 41)){
			return loanInfoService.updateStatus(loanId, 41,32);
		}
		return false;
	}
	
	public boolean updateStatusForOver(Long loanId){
		LoanVariation loanVariation  = this.getByLoanId(loanId);
		
		if(loanVariation.getStatus()!=42){
			return false;
		}
		
		if(this.updateStatus(loanVariation, 51)){
			return loanInfoService.updateStatus(loanId, 51,41);
		}
		return false;
	}
	private boolean updateStatus(LoanVariation loanVariation,int status){
		
		loanVariation.setOldStatus(loanVariation.getStatus());
		loanVariation.setStatus(status);
		return 1==this.loanVariationDao.updateStatus(loanVariation);
	}
	
	private boolean updateStatus(Long loanId,int status,int oldStatus){
		LoanVariation loanVariation = new LoanVariation();
		loanVariation.setLoanId(loanId);
		loanVariation.setStatus(status);
		loanVariation.setOldStatus(oldStatus);
		
		return 1==this.loanVariationDao.updateStatus(loanVariation);
	}

	@Override
	public LoanInfo getLoanInfoFromCache(Long lid) {
		String key = "LOAN_INFO_"+lid;
		Object o = defaultCache.getValue(key);
		LoanInfo loanInfo = null;
		if(o==null){
			loanInfo = this.loanInfoService.getLoanInfoById(lid);
			if(loanInfo!=null){
				defaultCache.add(key, loanInfo, 1*60);
			}
			
		}else{
			loanInfo = (LoanInfo)o;
		}
		return loanInfo;
	}
	
	@Override
	public void removetLoanInfoFromCache(Long lid) {
		String key = "LOAN_INFO_"+lid;
		defaultCache.delete(key);
	}

	public Map<Long,LoanVariation> findLoanVariationByIds(List<Long> loanIds){
		List<LoanVariation> list = loanVariationDao.findByLoanIds(loanIds);
		Map<Long,LoanVariation> map = new HashMap<Long,LoanVariation>();
		for(LoanVariation loanVariation:list){
			map.put(loanVariation.getLoanId(), loanVariation);
		}
		return map;
	}
	
	public boolean checkOverTime(LoanVariation loanVariation){
		Date tenderExpiredTime = loanVariation.getExpiredTime();
		
		Date now = new Date();
		
		int mimllis;
		try {
			mimllis = DateUtil.getMillisBetweenTwoDate(now, tenderExpiredTime);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.error("paramas exception ",e);
			return false;
		}
		
		if(mimllis>=0){
			return true;
		}
		
		return false;
	}
	@Override
	public List<LoanVariation> findExpiredLoan(){
		List<Integer> statusList = new ArrayList<Integer>();
		statusList.add(21);
		List<LoanVariation> tendingLoanList = this.findByStatus(statusList);
		List<LoanVariation> expiredLoanList = new ArrayList<LoanVariation>();
		long currentTime = System.currentTimeMillis();
		for(LoanVariation loanVariation:tendingLoanList){
			if(loanVariation.getExpiredTime()==null){
				logger.error("expired time null loanId="+loanVariation.getLoanId());
				continue;
			}
			if(loanVariation.getExpiredTime().getTime()<currentTime){
				expiredLoanList.add(loanVariation);
			}
		}
		return expiredLoanList;
	}
	
	
	public List<LoanVariation> findByStatus(List<Integer> status){
		return this.loanVariationDao.findByStatus(status);
	}

	@Override
	public boolean updateStatusForTimeExpired(Long lid) {
		
		if(this.updateStatus(lid, 31,21)){
			return loanInfoService.updateStatus(lid, 31);
		}
		return false;
	}

	@Override
	public List<LoanInfo> findCanTenderLoan() {
		List<LoanInfo> canTenderLoanList = new ArrayList<LoanInfo>();
		List<Integer> statusList = new ArrayList<Integer>();
		statusList.add(12);
		statusList.add(21);
		List<LoanInfo> list = loanInfoService.findByStatus(statusList);
		for(LoanInfo loanInfo:list){
			int result = loanInfo.checkStatusCanTender();
			if(result>0){
				if(0==loanInfo.getAuto()){
					canTenderLoanList.add(loanInfo);
				}
			}
		}
		return canTenderLoanList;
	}

}
